package doc;

import cn.demoncat.util.lang.entity.IdName;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.elasticsearch.annotations.*;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;

import java.io.Serializable;
import java.time.LocalDate;


// ElasticSearch的索引映射类：如果检查到POJO对应的索引不存在，就会根据POJO类的声明及注解来创建
// 建议：通过脚本创建mapping，不使用自动创建；只注解@Document声明文档类，使用@Id映射_id，使用@Field注解日期类
// 参数说明：https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html
@Document(
		// 索引名：对应元数据_index；全部小写，可以包含 - 和 _
		indexName = "user", 
		// 分片数：创建索引时使用，默认1
		shards = 1, 
		// 副本数：创建索引时使用，默认1
		replicas = 1, 
		// 索引刷新时间：创建索引时使用，默认1s
		refreshInterval = "1s", 
		// 是否创建索引：默认true
		createIndex = true)
// 指定文档映射（自动创建的mapping语法复杂，而且不支持IK分词器，需要指定mapping，或主动创建索引）
@Mapping(mappingPath = "es/user.json")
public class User implements Serializable{

	// 不参与映射的字段
	@Transient
	private static final long serialVersionUID = 1L;
	
	// 索引主键：对应元数据_id；如果字段和映射都叫id可以省略注解
	@Id
	private Long id;
	
	// 索引字段（有"自动创建索引、字段名不对应、格式化配置"等特殊需求时使用）
	@Field(
			// 字段名：默认为属性名
			name = "name",
			// 字段类型：默认FieldType.Auto，创建的索引通常不适用
			// 文档：https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html
			// 常用：Keyword 精确搜索；Text 分词搜索；Long 数值/日期
			type = FieldType.Text,
			// 日期格式化：默认为none，日期类型自定义格式为DateFormat.custom
			// ES使用long存储日期，为了避免时区和格式化问题，建议搜索日期用long，展示日期用String
			format = DateFormat.none,
			// 格式化："yyyy"使用"uuuu"，LocalDateTime为 "uuuu-MM-dd'T'HH:mm:ss"
			pattern = "",
			// Null默认值
			nullValue = "",
			// 将字段值复制到指定字段（指定字段做索引时，拼接本字段的值，两个字段的存储值都不变），这样指定字段就可以作为组合字段，以通过它查询多个字段的值
			copyTo = "content",
			// 是否索引：默认true
			index = true,
			// 是否存储：对字段进行单独存储，默认false（通过元数据_source文档可以查询到，但不会被单独存储）；如果只搜索单个或多个字段而非文档，可以设置为true
			// 文档：https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-store.html
			store = false,
			// 字符串字节长度限制：超过限制的字段将不被index和store（在文档元数据_source中可以查到），字符串数组表示每个元素的长度；Lucene最多支持32766
			ignoreAbove = 256,
			// 相似度算法：用于Text字段；ES和Lucene的默认算法是BM25
			similarity = Similarity.BM25,
			// 规定字段是否参与评分：默认true
			norms = true,
			// 设置前缀索引的字符数（默认2），以便加速前缀搜索：最少字符，最多字符
			indexPrefixes = @IndexPrefixes(minChars = 2, maxChars = 2),
			// 搜索分词器：query_ansj,ik_smart,ik_max_word
			searchAnalyzer = "",
			// 索引分词器：index_ansj,ik_smart,ik_max_word
			analyzer = "",
			// 标准分词器：对于Keyword，可以设置为"lowercase"，以便忽略大小于搜索
			normalizer = "")
	private String name;

	// 地理坐标：GeoPoint 类型
	private GeoPoint point;
	
	// 普通字段：即使不注解@Field，也会存储在文档数据中，主要用于"字段名不对应、格式化配置"，以及"自动创建索引"时指定类型及索引规则
	private String content;
	
	// 时间戳
	@Field(type = FieldType.Long)
	private Long timestamp;
	// yyyy
	@Field(type = FieldType.Integer)
	private Integer year;
	// yyyy-MM
	@Field(type = FieldType.Date, format = DateFormat.year_month)
	private String yearMonth;
	// yyyy-MM-dd
	@Field(type = FieldType.Date, format = DateFormat.date)
	private LocalDate date;
	// yyyy-MM-dd HH:mm:ss
	@Field(type = FieldType.Date, format = DateFormat.date_hour_minute_second)
	private java.time.LocalDateTime putTime;

	@Field(type = FieldType.Object)
	private IdName obj;
	
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public GeoPoint getPoint() {
		return point;
	}

	public void setPoint(GeoPoint point) {
		this.point = point;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}
}
